package com.huike.report.service.impl;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Predicate;


import com.huike.report.domain.vo.*;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.huike.business.mapper.TbBusinessMapper;
import com.huike.clues.domain.TbActivity;
import com.huike.clues.domain.TbAssignRecord;
import com.huike.clues.domain.TbClue;
import com.huike.clues.domain.vo.IndexStatisticsVo;
import com.huike.clues.mapper.SysDeptMapper;
import com.huike.clues.mapper.SysDictDataMapper;
import com.huike.clues.mapper.TbActivityMapper;
import com.huike.clues.mapper.TbAssignRecordMapper;
import com.huike.clues.mapper.TbClueMapper;
import com.huike.common.core.domain.entity.SysDept;
import com.huike.common.utils.SecurityUtils;
import com.huike.contract.domain.TbContract;
import com.huike.contract.mapper.TbContractMapper;
import com.huike.report.mapper.ReportMapper;
import com.huike.report.service.IReportService;

@Service
public class ReportServiceImpl implements IReportService {

    @Autowired(required = false)
    private TbContractMapper contractMapper;


    @Autowired(required = false)
    private SysDictDataMapper sysDictDataMapper;


    @Autowired(required = false)
    private TbClueMapper clueMapper;

    @Autowired(required = false)
    private TbActivityMapper activityMapper;


    @Autowired(required = false)
    private SysDeptMapper deptMapper;

    @Autowired(required = false)
    private TbAssignRecordMapper assignRecordMapper;

    @Autowired(required = false)
    private ReportMapper reportMpper;


    /**
     * 渠道统计
     */
    @Override
    public List<Map<String, Object>> chanelStatistics(String beginCreateTime, String endCreateTime) {
        List<Map<String, Object>> data = contractMapper.chanelStatistics(beginCreateTime, endCreateTime);
        for (Map<String, Object> datum : data) {
            String subjectValue = (String) datum.get("channel");
            String lable = sysDictDataMapper.selectDictLabel("clues_item", subjectValue);
            datum.put("channel", lable);
        }
        return data;
    }

    @Override
    public List<TbContract> contractReportList(TbContract tbContract) {
        return contractMapper.selectTbContractList(tbContract);
    }


    @Override
    public List<Map<String, Object>> activityStatistics(String beginCreateTime, String endCreateTime) {
        List<Map<String, Object>> data = contractMapper.activityStatistics(beginCreateTime, endCreateTime);
        for (Map<String, Object> datum : data) {
            Long activityId = (Long) datum.get("activity_id");
            TbActivity tbActivity = activityMapper.selectTbActivityById(activityId);
            if (tbActivity == null) {
                datum.put("activity", "其他");
            } else {
                datum.put("activity", tbActivity.getName());
            }
        }
        return data;
    }

    /**
     * 按照部门统计销售
     *
     * @param beginCreateTime
     * @param endCreateTime
     * @return
     */
    @Override
    public List<Map<String, Object>> deptStatisticsList(String beginCreateTime, String endCreateTime) {
        List<Map<String, Object>> data = contractMapper.deptStatistics(beginCreateTime, endCreateTime);
        for (Map<String, Object> datum : data) {
            Long deptId = (Long) datum.get("dept_id");
            if (deptId != null) {
                SysDept dept = deptMapper.selectDeptById(deptId);
                datum.put("deptName", dept.getDeptName());
            }
        }
        return data;
    }


    /**
     * 按照渠道统计销售
     *
     * @param beginCreateTime
     * @param endCreateTime
     * @return
     */
    @Override
    public List<Map<String, Object>> channelStatisticsList(String beginCreateTime, String endCreateTime) {
        List<Map<String, Object>> data = contractMapper.channelStatistics(beginCreateTime, endCreateTime);
        for (Map<String, Object> datum : data) {
            String subjectValue = (String) datum.get("channel");
            if (subjectValue != null) {
                String lable = sysDictDataMapper.selectDictLabel("clues_item", subjectValue);
                datum.put("channel", lable);
            }
        }
        return data;
    }


    /**
     * 按照归属人统计销售
     *
     * @param beginCreateTime
     * @param endCreateTime
     * @return
     */
    @Override
    public List<Map<String, Object>> ownerShipStatisticsList(String beginCreateTime, String endCreateTime) {
        return contractMapper.ownerShipStatistics(beginCreateTime, endCreateTime);
    }


    @Override
    public List<TbClue> cluesStatisticsList(TbClue clue) {
        return clueMapper.selectTbClueForReport(clue);
    }

    @Override
    public List<ActivityStatisticsVo> activityStatisticsList(TbActivity query) {
        query.setStatus("2");
        List<TbActivity> activities = activityMapper.selectTbActivityList(query);
        Map<String, Object> timeMap = query.getParams();
        List<ActivityStatisticsVo> list = new ArrayList<>();
        for (TbActivity activity : activities) {
            ActivityStatisticsVo dto = new ActivityStatisticsVo();
            BeanUtils.copyProperties(activity, dto);
            TbClue tbClue = new TbClue();
            tbClue.setActivityId(activity.getId());
            tbClue.setChannel(activity.getChannel());
            tbClue.setParams(timeMap);
            Map<String, Object> clueCount = clueMapper.countByActivity(tbClue);
            if (clueCount != null) {
                dto.setCluesNum(Integer.parseInt(clueCount.get("total").toString()));
                if (clueCount.get("falseClues") != null) {
                    dto.setFalseCluesNum(Integer.parseInt(clueCount.get("falseClues").toString()));
                }
                if (clueCount.get("toBusiness") != null) {
                    dto.setBusinessNum(Integer.parseInt(clueCount.get("toBusiness").toString()));
                }
            }
            TbContract tbContract = new TbContract();
            tbContract.setChannel(activity.getChannel());
            tbContract.setActivityId(activity.getId());
            tbContract.setParams(timeMap);
            Map<String, Object> contractCount = contractMapper.countByActivity(tbContract);
            if (contractCount != null) {
                dto.setCustomersNum(Integer.parseInt(contractCount.get("customersNum").toString()));
                if (contractCount.get("amount") == null) {
                    dto.setAmount(0d);
                } else {
                    dto.setAmount((Double) contractCount.get("amount"));
                }
                if (contractCount.get("cost") == null) {
                    dto.setCost(0d);
                } else {
                    dto.setCost((Double) contractCount.get("cost"));
                }

            }
            list.add(dto);
        }
        return list;
    }


    @Override
    public IndexVo getIndex(IndexStatisticsVo request) {
        Long deptId = request.getDeptId();
        TbAssignRecord tbAssignRecord = new TbAssignRecord();
        tbAssignRecord.setLatest("1");
        assignRecordMapper.selectAssignRecordList(tbAssignRecord);
        return null;
    }


    /**
     * 获取首页基本数据
     *
     * @param beginCreateTime
     * @param endCreateTime
     * @return
     */
    @Override
    public IndexBaseInfoVO getBaseInfo(String beginCreateTime, String endCreateTime) {

        //1 构建一个空的结果集对象
        IndexBaseInfoVO result = new IndexBaseInfoVO();
        //2 封装结果集属性
        // 2.1 由于查询需要用到用户名 调用工具类获取用户名
        String username = SecurityUtils.getUsername();
        // 2.2 开始查询第一个属性 线索数量
        result.setCluesNum(reportMpper.getCluesNum(beginCreateTime, endCreateTime, username));
        // 2.3 开始查询第一个属性 商机数量
        result.setBusinessNum(reportMpper.getBusinessNum(beginCreateTime, endCreateTime, username));
        // 2.4 开始查询第一个属性 合同数量
        result.setContractNum(reportMpper.getContractNum(beginCreateTime, endCreateTime, username));
        // 2.5 开始查询第一个属性 销售金额数量
        result.setSalesAmount(reportMpper.getSalesAmount(beginCreateTime, endCreateTime, username));
        //5 返回结果集对象
        return result;
    }

    /**
     * 获取当天数据
     *
     * @return
     */
    @Override
    public IndexVo getTodayInfo() {
        //构建结果集对象
        IndexVo indexVo = new IndexVo();
        //获取用户
        String username = SecurityUtils.getUsername();
        try {
            CompletableFuture<Integer> cluesNums = CompletableFuture.supplyAsync(() -> {
                //获得当天的线索数量
                return reportMpper.getTodayClueNum(username);
            });
            CompletableFuture<Integer> businessNum = CompletableFuture.supplyAsync(() -> {
                //获得当天的商机数量
                return reportMpper.getTodayBusinessNum(username);
            });
            CompletableFuture<Integer> contractNum = CompletableFuture.supplyAsync(() -> {
                //获得当天的合同数量
                return reportMpper.getTodayContractNum(username);
            });
            CompletableFuture<Double> salesAmount = CompletableFuture.supplyAsync(() -> {
                //获得当天的合同金额数量
                return reportMpper.getTodaySalesAmount(username);
            });
            CompletableFuture.allOf(cluesNums,
                    businessNum,
                    contractNum,
                    salesAmount).join();
            //设置线索的数量
            indexVo.setTodayCluesNum(cluesNums.get());
            //设置的商机数量
            indexVo.setTodayBusinessNum(businessNum.get());
            //设置的合同数量
            indexVo.setTodayContractNum(contractNum.get());
            //设置的合同金额数量
            indexVo.setTodaySalesAmount(salesAmount.get());
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

        //返回结果
        return indexVo;
    }

    /**
     * 待办的数据
     *
     * @return
     */
    @Override
    public IndexVo getTodoInfo(String beginCreateTime, String endCreateTime) {
        //构建结果集对象
        IndexVo indexVo = new IndexVo();
        //获取用户
        String username = SecurityUtils.getUsername();
        //获取待跟进线索信息

        Integer todoClue = reportMpper.getTodoClue(beginCreateTime, endCreateTime, username);
        indexVo.setTofollowedCluesNum(todoClue);
        //获取待跟进商机
        Integer todoBusiness = reportMpper.getTodoBusiness(beginCreateTime, endCreateTime, username);
        indexVo.setTofollowedBusinessNum(todoBusiness);
        //获得待分配线索
        Integer allClue = reportMpper.getAllClue(beginCreateTime, endCreateTime, username);
        indexVo.setToallocatedCluesNum(allClue);
        //2获得待分配商机
        Integer allBuseiness = reportMpper.getAllBuseiness(beginCreateTime, endCreateTime, username);
        indexVo.setToallocatedBusinessNum(allBuseiness);
        return indexVo;

    }

    /**
     * 最欢迎的学科统计图
     *
     * @param beginCreateTime
     * @param endCreateTime
     * @return
     */
    @Override
    public List<SubjectVo> getSubjectVoList(String beginCreateTime, String endCreateTime) {
        List<SubjectVo> allBySubject = reportMpper.getAllBySubject(beginCreateTime, endCreateTime);
        return allBySubject;

    }


    //统计返回内所有日期的方法
    public List<String> findAllDate(String beginCreateTime, String endCreateTime) throws ParseException {
        //给一个放所有时间的集合
        ArrayList<String> timeList = new ArrayList<>();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        //解析时间
        Date startTime = dateFormat.parse(beginCreateTime);
        Date endTime = dateFormat.parse(endCreateTime);
        //开始时间添加到集合
        timeList.add(dateFormat.format(startTime));
        //设置开始时间
        Calendar st = Calendar.getInstance();
        st.setTime(startTime);
        //如果的结束时间是在开始时间后面，就后让开始时间加一天，然后在添加到集合
        while (endTime.after(st.getTime())) {
            st.add(Calendar.DAY_OF_MONTH, 1);
            timeList.add(dateFormat.format(st.getTime()));
        }
        return timeList;
    }

    /**
     * 获得新增的线索和总数
     *
     * @param beginCreateTime
     * @param endCreateTime
     * @return
     */
    @Override
    public ClueAllVo getClueAllVoList(String beginCreateTime, String endCreateTime) {
        //创建一个封装返回对象
        ClueAllVo clueAllVo = new ClueAllVo();
        //活动所有的时间
        try {
            List<String> allDate = findAllDate(beginCreateTime, endCreateTime);
            //获得所有新线索数量和时间
            List<Map<String, Object>> newClueList =
                    reportMpper.findAllClue(beginCreateTime, endCreateTime);

            //获得新增线索和总数线索集合
            List<SeriesAll> series = clueAllVo.getSeries();
            //设置所有的时间集合
            clueAllVo.setXAxis(allDate);
            //设置新增线索和总数线索名字
            SeriesAll newSeries = new SeriesAll();
            newSeries.setName("新增线索数量");
            SeriesAll seriesAll = new SeriesAll();
            seriesAll.setName("线索总数量");
            //设置新增线索每天的数量和总线索每天的数
            //遍历所有返回时间
            //定义线索总数的时间
            int sum=0;
            for (String s : allDate) {
                //这里通过过滤得到新增线索时间和每天的时间进行匹配
                //这里判断它是不是和有新增线索的时间匹配的上。
                Optional<Map<String, Object>> optional = newClueList.stream().filter(new Predicate<Map<String, Object>>() {
                    @Override
                    public boolean test(Map<String, Object> clue) {
                        return clue.get("ct").equals(s);
                        //这里是拿到第一个匹配的时间map
                    }
                }).findFirst();
                //①、如果匹配的上就有值，就设置新增线索的值为该值
                if (optional.isPresent()){
                    //获取匹配的map
                    Map<String, Object> stringObjectMap = optional.get();
                    //活动新增线索时间的值
                    Object num = stringObjectMap.get("num");
                    //获得新增线索集合。添加数据
                    List<Integer> data = newSeries.getData();
                    data.add(Integer.parseInt(num.toString()));
                    //总数加上新增线索数
                    sum+=Integer.parseInt(stringObjectMap.get("num").toString());
                }else {
                    //1、如果没匹配上就设置值为0
                    newSeries.getData().add(0);
                }
                    //2、总数也设置0
                    //②、累加总数
                    seriesAll.getData().add(sum);
            }
            //封装完数据添加到返回的对象
            series.add(newSeries);
            series.add(seriesAll);
            clueAllVo.setSeries(series);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return clueAllVo;
    }

    /**
     * 获取转化率图表
     *
     * @param beginCreateTime
     * @param endCreateTime
     * @return
     */
    @Override
    public MapVo findMapVo(String beginCreateTime, String endCreateTime) {
        //创建返回的结果对象
        MapVo mapVo = new MapVo();
        //线索数量
        try {
            CompletableFuture<Integer> cluesNums1 = CompletableFuture.supplyAsync(()->{
               return reportMpper.cluesNums(beginCreateTime,endCreateTime);
            });
            //有效线索数
            CompletableFuture<Integer> businessNums1 = CompletableFuture.supplyAsync(()->{
                return reportMpper.businessNums(beginCreateTime,endCreateTime);
            });
            //商机数量
            CompletableFuture<Integer> effectiveCluesNums1 = CompletableFuture.supplyAsync(()->{
                return reportMpper.effectiveCluesNums(beginCreateTime,endCreateTime);
            });
            //合同数量
            CompletableFuture<Integer> contractNums1 = CompletableFuture.supplyAsync(()->{
                return  reportMpper.contractNums(beginCreateTime,endCreateTime);
            });
            //阻塞获取数据
            CompletableFuture.allOf(cluesNums1,
                    businessNums1,
                    effectiveCluesNums1,
                    contractNums1).join();
            //封装数据
            mapVo.setCluesNums(cluesNums1.get());
            mapVo.setBusinessNums(businessNums1.get());
            mapVo.setEffectiveCluesNums(effectiveCluesNums1.get());
            mapVo.setContractNums(contractNums1.get());
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        System.out.println(mapVo.toString());
        return mapVo;
    }
}